--[[
Origional Code by Evl, we thank you for your time and efforts put into this
Additional Modifications by Nirek & Mist, we thank them for adding things that the masses wanted
    --Emphasizing code taken from BigWigs -- thanks to the devs for their work :D
    --Optional Fubar support added by Orionshock

]]--

local L = AceLibrary("AceLocale-2.2"):new("Hourglass")

if AceLibrary:HasInstance("FuBarPlugin-2.0")then
    Hourglass = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceDB-2.0", "AceConsole-2.0", "CandyBar-2.0", "Sink-1.0", "FuBarPlugin-2.0")
else
    Hourglass = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceDB-2.0", "AceConsole-2.0", "CandyBar-2.0", "Sink-1.0")
end

local Gratuity = AceLibrary("Gratuity-2.0")
local CandyBar = AceLibrary("CandyBar-2.0")
local Dewdrop = AceLibrary("Dewdrop-2.0")
local SharedMedia = AceLibrary("SharedMedia-1.0")

local paint = AceLibrary("PaintChips-2.0")

local DURATION = 0.5
local _abs, _cos, _pi = math.abs, math.cos, math.pi

local new, del
do
	local cache = setmetatable({},{__mode="k"})
	function new()
		local t = next(cache)
		if t then
			cache[t] = nil
			return t
		else
			return {}
		end
	end
	function del(t)
		for k in pairs(t) do
			t[k] = nil
		end
		cache[t] = true
		return nil
	end
end

local function print(msg) DEFAULT_CHAT_FRAME:AddMessage(msg) end

local flashTimers = nil
local emphasizeTimers = nil
local movingBars = nil

local anchor = nil
local emphasizeAnchor = nil

local function shouldDisableEmphasizeOption()
	return not Hourglass.db.profile.emphasize
end

local options = {
	type = "group",
	args = {
		anchor = {
			type = "toggle",
			name = L["Show anchor"],
			desc = L["Show the bar anchor frame."],
			get = function() return anchor and anchor:IsShown() end,
			set = function(v) Hourglass:ToggleAnchor(v) end,
			order = 1,
		},
		min = {
			type = "text",
			name = L["Minimum duration"],
			desc = L["Minimum cooldown duration to display."],
			usage = L["<seconds>"],
			get = function () return Hourglass.db.profile.min end,
			set = function (v) Hourglass.db.profile.min = tonumber(v) end,
			order = 2,
		},
		max = {
			type = "text",
			name = L["Maximum duration"],
			desc = L["Maximum cooldown duration to display."],
			usage = L["<seconds>"],
			get = function () return Hourglass.db.profile.max end,
			set = function (v) Hourglass.db.profile.max = tonumber(v) end,
			order = 3,
		},
		bars = {
			type = "group",
			name = L["Bar settings"],
			desc = L["Bar settings."],
			args = {
				growth = {
					type = "toggle",
					name = L["Grow upwards"],
					desc = L["Toggle bars grow upwards/downwards from anchor."],
					get = function () return Hourglass.db.profile.growth end,
					set = function (v)
						Hourglass.db.profile.growth = v
						Hourglass:SetCandyBarGroupGrowth("Hourglass", Hourglass.db.profile.growth)
					end,
					order = 1,
				},
		                width = {
		                        type = "range",
		                        name = L["Width"],
		                        desc = L["Set the width of the bars."],
		                        get = function() return Hourglass.db.profile.width end,
		                        set = function(v)
						      Hourglass.db.profile.width = v
						      for key, barId in ipairs(CandyBar.groups["Hourglass"].bars) do
							      Hourglass:SetCandyBarWidth(barId, Hourglass.db.profile.width)
						      end
					      end,
		                        min = 50,
		                        max = 400,
		                        step = 5,
		                        isPercent = false,
					order = 2,
		                },
		                height = {
		                        type = "range",
		                        name = L["Height"],
		                        desc = L["Set the height of the bars."],
		                        get = function() return Hourglass.db.profile.height end,
		                        set = function(v)
						      Hourglass.db.profile.height = v
						      for key, barId in ipairs(CandyBar.groups["Hourglass"].bars) do
							      Hourglass:SetCandyBarHeight(barId, Hourglass.db.profile.height)
						      end
					      end,
		                        min = 5,
		                        max = 25,
		                        step = 1,
		                        isPercent = false,
					order = 3,
		                },
		                scale = {
		                        type = "range",
		                        name = L["Scale"],
		                        desc = L["Set the scale of the bars."],
		                        get = function() return Hourglass.db.profile.scale end,
		                        set = function(v)
						      Hourglass.db.profile.scale = v
						      for key, barId in ipairs(CandyBar.groups["Hourglass"].bars) do
							      Hourglass:SetCandyBarScale(barId, Hourglass.db.profile.scale)
						      end

					      end,
		                        min = 0.25,
		                        max = 3,
		                        step = 0.05,
		                        isPercent = true,
					order = 4,
		                },
				texture = {
					type = "text",
					name = L["Texture"],
					desc = L["Set the texture for the timer bars."],
					get = function () return Hourglass.db.profile.texture end,
					set = function (v) Hourglass.db.profile.texture = v
						for key, barId in ipairs(CandyBar.groups["Hourglass"].bars) do
							Hourglass:SetCandyBarTexture(barId, SharedMedia:Fetch("statusbar", Hourglass.db.profile.texture))
						end
					end,
					validate = SharedMedia:List("statusbar"),
					order = 5,
				},
		                fontsize  = {
		                        type = "range",
		                        name = L["Font size"],
		                        desc = L["Set the size of the bar text."],
		                        get = function() return Hourglass.db.profile.fontsize end,
					set = function (v) Hourglass.db.profile.fontsize = v
						for key, barId in ipairs(CandyBar.groups["Hourglass"].bars) do
							Hourglass:SetCandyBarFontSize(barId, v)
						end
					end,
		                        min = 6,
		                        max = 24,
		                        step = 1,
		                        isPercent = false,
					order = 7,
		                },
				timeOnly = {
					type = "toggle",
					name = L["Hide spell/item name"],
					desc = L["Don't show spell/item name on the bar."],
					get = function () return Hourglass.db.profile.timeOnly end,
					set = function (v) Hourglass.db.profile.timeOnly = v end,
					order = 8,
				},
			},
			order = 10,
		},
		announce = {
			type = "group",
			name = L["Announce"],
			desc = L["Cooldown expiry announces."],
			args = {
				text = {
					type = "group",
					name = L["Text"],
					desc = L["Announce cooldown expiry as text."],
					args = {
						display = {
							type = "text",
							name = L["Display"],
							desc = L["Select where to announce cooldown expiry."],
							validate = {"None", "Parrot", "SCT", "SCT Message", "MSBT", "Error Frame"},
							get = function () return Hourglass.db.profile.display end,
							set = function (v) Hourglass.db.profile.display = v end,
							order = 1,
						},
						colour = {
							type = "color",
							name = L["Colour"],
							desc = L["Text message colour"],
							get = function()
								      return Hourglass.db.profile.colour.red, Hourglass.db.profile.colour.green, Hourglass.db.profile.colour.blue
							      end,
							set = function(r, g, b)
								      Hourglass.db.profile.colour.red, Hourglass.db.profile.colour.green, Hourglass.db.profile.colour.blue = r, g, b
							      end,
							order = 2,
						},
					},
				},
				emphasize = {
					type = "group",
					name = L["Emphasize"],
					desc = L["Emphasize bars that are close to completion."],
					args = {
						emphasize = {
							type = "toggle",
							name = L["Enable"],
							desc = L["Enables emphasizing bars."],
							get = function() return Hourglass.db.profile.emphasize end,
							set = function(v) Hourglass.db.profile.emphasize = v end,
							order = 10,
						},
						flash = {
							type = "toggle",
							name = L["Flash"],
							desc = L["Flashes the background red for bars that are emphasized."],
							get = function() return Hourglass.db.profile.emphasizeFlash end,
							set = function(v) Hourglass.db.profile.emphasizeFlash = v end,
							disabled = shouldDisableEmphasizeOption,
							order = 20,
						},
						move = {
							type = "toggle",
							name = L["Move"],
							desc = L["Move bars that are emphasized to a second anchor."],
							get = function() return Hourglass.db.profile.emphasizeMove end,
							set = function(v) Hourglass.db.profile.emphasizeMove = v end,
							disabled = shouldDisableEmphasizeOption,
							order = 30,
						},
						scale = {
							type = "range",
							name = L["Scale"],
							desc = L["Set the scale for emphasized bars."],
							min = 0.2,
							max = 2.0,
							step = 0.1,
							get = function() return Hourglass.db.profile.emphasizeScale end,
							set = function(v) Hourglass.db.profile.emphasizeScale = v end,
							disabled = function()
								if not Hourglass.db.profile.emphasizeMove then return true end
								return not Hourglass.db.profile.emphasize
							end,
							order = 40,
						},
						time = {
							type = "range",
							name = L["Time"],
							desc = L["Time left on cooldown when bars are emphasized."],
							min = 1,
							max = 10,
							step = 1,
							isPercent = false,
							get = function() return Hourglass.db.profile.emphasizeTime end,
							set = function(v) Hourglass.db.profile.emphasizeTime = v end,
							disabled = shouldDisableEmphasizeOption,
							order = 50,
						},
						growup = {
							type = "toggle",
							name = L["Grow upwards"],
							desc = L["Toggle bars grow upwards/downwards from anchor."],
							get = function() return Hourglass.db.profile.emphasizeGrowup end,
							set = function(v) Hourglass.db.profile.emphasizeGrowup = v end,
							disabled = function()
								if not Hourglass.db.profile.emphasizeMove then return true end
								return not Hourglass.db.profile.emphasize
							end,
							order = 60,
						},
					},
				},
			},
			order = 20,
		},
                test = {
			type = "execute",
			name = L["Test"],
			desc = L["Test bars."],
			func = function()
				       Hourglass:TestBars()
			       end,
		},
		show = {
			type = "group",
			name = L["Show cooldowns"],
			desc = L["Toggle showing cooldown types."],
			args = {
				spells = {
					type = "group",
					name = L["Spells"],
					desc = L["Player spells cooldown options."],
					args = {
						enable = {
							type = "toggle",
							name = L["Enable player spells"],
							desc = L["Toggle showing player spells cooldowns."],
							get = function () return Hourglass.db.profile.showSpells end,
							set = function (v)
								      Hourglass.db.profile.showSpells = v
								      Hourglass:SPELL_UPDATE_COOLDOWN()
							      end,
							order = 10,
						},
						school = {
							type = "toggle",
							name = L["Show school"],
							desc = L["Spawns single bar if a school is locked."],
							get = function () return Hourglass.db.profile.school end,
							set = function (v)
								      Hourglass.db.profile.school = v
								      Hourglass:ScanSpells()
							      end,
							disabled = function ()
									   return not Hourglass.db.profile.showSpells
								   end,
							order = 100,
						},
					},
					order = 10,
				},
				petspells = {
					type = "toggle",
					name = L["Pet spells"],
					desc = L["Toggle showing pet cooldowns."],
					get = function () return Hourglass.db.profile.showPet end,
					set = function (v)
						Hourglass.db.profile.showPet = v
						Hourglass:PET_BAR_UPDATE_COOLDOWN()
					end,
					order = 20,
				},
				equipped = {
					type = "toggle",
					name = L["Equipped items"],
					desc = L["Toggle showing equipped items cooldowns."],
					get = function () return Hourglass.db.profile.showItems end,
					set = function (v)
						Hourglass.db.profile.showItems = v
					end,
					order = 30,
				},
				bags = {
					type = "toggle",
					name = L["Inventory items"],
					desc = L["Toggle showing inventory items cooldowns."],
					get = function () return Hourglass.db.profile.showBags end,
					set = function (v)
						Hourglass.db.profile.showBags = v
					end,
					order = 40,
				},
			},
			order = 30,
		},
	},
}

--~ FubarJunk here
if AceLibrary:HasInstance("FuBarPlugin-2.0") then
    Hourglass.hasIcon  = "Interface\\Icons\\INV_Gizmo_KhoriumPowerCore"
    Hourglass.OnMenuRequest = options
end

local select = select
local pairs = pairs
local spells = {}
local petspells = {}
local items = {}
local itemSlots = {"Trinket0Slot", "Trinket1Slot"}

local groupedCooldowns = {
 	[" Trap$"] = L["Traps"],
 	[" Shock$"] = L["Shocks"],
     --Warrior CD Retaliation , Sheild Wall, Recklessness AKA 'The Big Three'
    [L["Retaliation"]] = L["The Big Three"],
    [L["Shield Wall"]] = L["The Big Three"],
    [L["Recklessness"]] = L["The Big Three"]



}
-- Add Item group cooldowns here, items with the same = name will be merged into that grouping.
local groupedBagCooldowns = {
    --Mage Mana Gems
    [L["Mana Jade"]] = L["Mana Gems"],
    [L["Mana Ruby"]] = L["Mana Gems"],
    [L["Mana Citrine"]] = L["Mana Gems"],
    [L["Mana Agate"]] = L["Mana Gems"],
    [L["Manna Emerald"]] = L["Mana Gems"],
    [L["Thistle Teaa"]] = L["Mana Gems"],
    [" Healthstone$"] = L["Healthstone"],

    --Potions
	[L["Potion"]] = L["Potions"],
    [L["Blue Ogre Brew Special"]]= L["Potions"],  --Ogri'la
    [L["Red Ogre Brew Special"]] = L["Potions"],  --Ogri'la
    [L["Blue Ogre Brew"]]= L["Potions"],  --Ogri'la
    [L["Red Ogre Brew"]] = L["Potions"],  --Ogri'la
    [L["Bottled Nethergon Energy"]] = L["Potions"],  --TempistKeep
    [L["Bottled Nethergon Vapor"]] = L["Potions"],   --TempistKeep
    [L["Cenarion Mana Salve"]] = L["Potions"],   --CC
    [L["Cenarion Healing Salve"]] = L["Potions"],   --CC
    [L["Major Healing Draught"]] = L["Potions"],   --PvP
    [L["Major Mana Draught"]] = L["Potions"],   --PvP
    [L["Superior Mana Draught"]] = L["Potions"],   --PvP
    [L["Superior Healing Draught"]] = L["Potions"],   --PvP

    --Mounts
	[L["Warhorse"]] = L["Mount"],
	[L["Drake"]] = L["Mount"],
    [L["Windrider"]] = L["Mount"]
}
local chainedCooldowns = {
	[L["Cold Snap"]] = { L["Cone of Cold"], L["Frost Nova"], L["Frost Ward"], L["Ice Barrier"], L["Ice Block"], L["Summon Water Elemental"] },
	[L["Preparation"]] = { L["Cold Blood"], L["Distract"], L["Evasion"], L["Feint"], L["Gouge"], L["Kick"], L["Kidney Shot"], L["Sprint"], L["Vanish"] },
	[L["Readiness"]] = { L["Intimidation"], L["Kill Command"], L["Scare Beast"], L["Aimed Shot"], L["Arcane Shot"], L["Concussive Shot"], L["Distracting Shot"], L["Flare"], L["Multi-Shot"], L["Rapid Fire"], L["Tranquilizing Shot"], L["Viper Sting"], L["Volley"], L["Counterattack"], L["Deterrence"], L["Disengage"], L["Explosive Trap"], L["Feign Death"], L["Freezing Trap"], L["Frost Trap"], L["Immolation Trap"], L["Misdirection"], L["Mongoose Bite"], L["Raptor Strike"], L["Snake Trap"], L["Wyvern Sting"] },
}

-- Lists the magic schools, with 1 spell for each (the spell should have no default cooldown)
local schoolGroups = {
	["WARLOCK"] = {
		[L["Shadow"]] = L["Shadow Bolt"],
		[L["Fire"]] = L["Searing Pain"],
	},
	["MAGE"] = {
		[L["Arcane"]] = L["Arcane Missiles"],
		[L["Fire"]] = L["Fireball"],
		[L["Frost"]] = L["Frostbolt"],
	},
    ["DRUID"] = {
        [L["Nature"]] = L["Healing Touch"],
    },
	["SHAMAN"] = {
		[L["Physical"]] = L["Wrath of Air Totem"],
		[L["Fire"]] = L["Flametongue Totem"],
		[L["Frost"]] = L["Healing Stream Totem"],
		[L["Nature"]] = L["Lightning Bolt"],

	},
	["PRIEST"] = {
		[L["Shadow"]] = L["Shadow Word: Pain"],
	},
}

-- Lists the spells that have a default cooldown, and the school they belong to
local schoolSpells = {
	["WARLOCK"] = {
		[L["Shadow Ward"]] = L["Shadow"],
		[L["Howl of Terror"]] = L["Shadow"],
		[L["Shadowburn"]] = L["Shadow"],
		[L["Ritual of Doom"]] = L["Shadow"],
		[L["Curse of Doom"]] = L["Shadow"],
		[L["Ritual of Souls"]] = L["Shadow"],
		[L["Amplify Curse"]] = L["Shadow"],
		[L["Death Coil"]] = L["Shadow"],
		[L["Soulshatter"]] = L["Shadow"],
		[L["Inferno"]] = L["Shadow"],
		[L["Soul Fire"]] = L["Fire"],
	},
	["MAGE"] = {
		[L["Frost Nova"]] = L["Frost"],
		[L["Cone of Cold"]] = L["Frost"],
		[L["Frost Ward"]] = L["Frost"],
		[L["Ice Barrier"]] = L["Frost"],
		[L["Ice Block"]] = L["Frost"],
		[L["Summon Water Elemental"]] = L["Frost"],
		[L["Fire Ward"]] = L["Fire"],
		[L["Fire Blast"]] = L["Fire"],
		[L["Blast Wave"]] = L["Fire"],
		[L["Portal: Stormwind"]] = L["Arcane"],
		[L["Portal: Ironforge"]] = L["Arcane"],
		[L["Portal: Darnassus"]] = L["Arcane"],
		[L["Portal: Exodar"]] = L["Arcane"],
		[L["Portal: Orgrimmar"]] = L["Arcane"],
		[L["Portal: Silvermoon"]] = L["Arcane"],
		[L["Portal: Thunder Bluff"]] = L["Arcane"],
		[L["Portal: Undercity"]] = L["Arcane"],
		[L["Portal: Shattrath"]] = L["Arcane"],
		[L["Blink"]] = L["Arcane"],
		[L["Counterspell"]] = L["Arcane"],
		[L["Evocation"]] = L["Arcane"],
		[L["Arcane Power"]] = L["Arcane"],
		[L["Invisibility"]] = L["Arcane"],
	},
    ["DRUID"] = {
        [L["Innervate"]] = L["Nature"],
        [L["Rebirth"]] = L["Nature"],
        [L["Faerie Fire (Feral)"]] = L["Nature"],
        [L["Tranquility"]] = L["Nature"],
        [L["Barkskin"]] = L["Nature"],
--~         [L["Nature's Grasp"] = L["Nature"],
        [L["Huricane"]] = L["Nature"],
    },
	["SHAMAN"] = {
		[L["Nature's Swiftness"]] = L["Physical"],
		[L["Shamanistic Rage"]] = L["Physical"],
		[L["Stormstrike"]] = L["Physical"],
		[L["Fire Elemental Totem"]] = L["Fire"],
		[L["Fire Nova Totem"]] = L["Fire"],
		[L["Flame Shock"]] = L["Fire"],
		[L["Frost Shock"]] = L["Frost"],
		[L["Mana Tide Totem"]] = L["Frost"],
		[L["Earth Elemental Totem"]] = L["Nature"],
		[L["Earth Shock"]] = L["Nature"],
		[L["Astral Recall"]] = L["Nature"],
		[L["Bloodlust"]] = L["Nature"],
		[L["Earthbind Totem"]] = L["Nature"],
		[L["Elemental Mastery"]] = L["Nature"],
		[L["Heroism"]] = L["Nature"],
		[L["Grounding Totem"]] = L["Nature"],
		[L["Reincarnation"]] = L["Nature"],
		[L["Stoneclaw Totem"]] = L["Nature"],
		[L["Chain Lightning"]] = L["Nature"],
	},
	["PRIEST"] = {
	[L["Fade"]] = L["Shadow"],
	[L["Shadow Word: Pain"]] = L["Shadow"],
	[L["Shadow Word: Death"]] = L["Shadow"],
	[L["Mind Blast"]] = L["Shadow"],
	[L["Mind Flay"]] = L["Shadow"],
	[L["Shadowfiend"]] = L["Shadow"],
	[L["Vampiric Embrace"]] = L["Shadow"],
	},

}
local playerClass

function Hourglass:OnInitialize()
	local defaults = {
		min = 2.5,
		max = 3600,
		growth = true,
		texture = "default",
		x = nil,
		y = nil,
		scale = 1,
		width = 200,
		height = 16,
		fontsize = 11,
		timeOnly = false,
		display = "SCT",
		colour = { red = 1, green = 0, blue = 0 },
		school = true,
		emphasize = true,
		emphasizeMove = true,
		emphasizeFlash = true,
		emphasizePosX = nil,
		emphasizePosY = nil,
		emphasizeScale = 1.5,
		emphasizeTime = 5,
		emphasizeGrowup = false,
		showSpells = true,
		showPet = true,
		showItems = true,
		showBags = true,
	}

	self:RegisterDB("HourglassDB")
	self:RegisterDefaults("profile", defaults)
	self:RegisterChatCommand("/hourglass", {type = "execute", func = "ShowOptions"})
	Dewdrop:Register("Hourglass", "children", options, "cursorX", true, "cursorY", true)

	self:CreateAnchor()
	self:RegisterCandyBarGroup("Hourglass")
	self:SetCandyBarGroupPoint("Hourglass", "TOP", anchor, "BOTTOM", 0, 0)
	self:SetCandyBarGroupGrowth("Hourglass", self.db.profile.growth)
end

function Hourglass:OnEnable()
	self:RegisterEvent("SPELLS_CHANGED")
	self:RegisterEvent("PLAYER_ENTERING_WORLD")
	self:RegisterEvent("SPELL_UPDATE_COOLDOWN")
	self:RegisterEvent("PET_BAR_UPDATE_COOLDOWN")
	self:RegisterEvent("ZONE_CHANGED_NEW_AREA")
	self:RegisterEvent("BAG_UPDATE_COOLDOWN")
	self:RegisterEvent("UNIT_INVENTORY_CHANGED")

	flashTimers = new()
	emphasizeTimers = new()
	movingBars = new()

	_, playerClass = UnitClass("player")
    options.args.output = AceLibrary("Sink-1.0"):GetAceOptionsDataTable(self).output
end

function Hourglass:SPELLS_CHANGED()
	self:ScanSpells()
	self:ScanPetSpells()
end

function Hourglass:PLAYER_ENTERING_WORLD()
	self:ScanSpells()
	self:ScanPetSpells()
	if self.db.profile.showItems then
		self:ScanItems()
	end
	if self.db.profile.showBags then
		self:ScanBags()
	end
end


function Hourglass:SPELL_UPDATE_COOLDOWN()
	if not self.db.profile.showSpells then return end

	local schoolCooldown = {}
	local schoolEnabled = self.db.profile.school

	if schoolEnabled and schoolGroups[playerClass] then
		for schoolName, spellName in pairs(schoolGroups[playerClass]) do
			local data = spells[spellName]
			if data then
				local startTime, duration, enable = GetSpellCooldown(data.id, BOOKTYPE_SPELL)
				if enable == 1 and duration > self.db.profile.min and duration <= self.db.profile.max and data.startTime ~= startTime then
					schoolCooldown[schoolName] = true
					data.startTime = startTime
					self:StartBar(schoolName..L[" School"], data, duration)
				end
			end
		end
	end

	for spellName, data in pairs(spells) do
		local startTime, duration, enable = GetSpellCooldown(data.id, BOOKTYPE_SPELL)
		if enable == 1 and duration > self.db.profile.min and duration <= self.db.profile.max and data.startTime ~= startTime then
			data.startTime = startTime
			if not schoolEnabled or not (data.school and schoolCooldown[data.school]) then
				self:StartBar(spellName, data, duration)
			end
		end
	end

end

function Hourglass:PET_BAR_UPDATE_COOLDOWN()
	if not self.db.profile.showPet then return end

	for spellName, data in pairs(petspells) do
		local startTime, duration, enable = GetSpellCooldown(data.id, BOOKTYPE_PET)

		if enable == 1 and duration > self.db.profile.min and duration <= self.db.profile.max and data.startTime ~= startTime then
			data.startTime = startTime
			self:StartBar(spellName, data, duration)
		end
	end
end

function Hourglass:UNIT_SPELLCAST_SUCCEEDED(unit, spellName)
	if unit == "player" and chainedCooldowns[spellName] then
		for _, chainedSpellName in pairs(chainedCooldowns[spellName]) do
			self:StopCandyBar(self:GetBarId(chainedSpellName))
			self:CancelScheduledEvent(self:GetBarId(chainedSpellName))
		end
	end
end

function Hourglass:ZONE_CHANGED_NEW_AREA()
	local zone = GetRealZoneText()

	if zone == nil or zone == "" then
		self:ScheduleEvent(self.ZONE_CHANGED_NEW_AREA, 5, self)
	elseif (strfind(zone, "Arena") or strfind(zone, "Ruins of Lordaeron")) then
		for key, barId in ipairs(CandyBar.groups["Hourglass"].bars) do
			if CandyBar.handlers[barId].time <= 600 then
				self:StopCandyBar(barId)
				self:CancelScheduledEvent(barId)
			end
		end
	end
end

function Hourglass:UNIT_INVENTORY_CHANGED(unit)
	if unit == "player" then
		if self.db.profile.showItems then
			self:ScanItems()
		end
		if self.db.profile.showBags then
			self:ScanBags()
		end
	end
end

function Hourglass:BAG_UPDATE_COOLDOWN(container)
	if self.db.profile.showItems then
		self:ScanItems()
	end
	if self.db.profile.showBags then
		self:ScanBags()
	end
end

function Hourglass:ScanSpells()
	spells = {}

	local i = 1

	local spellName = GetSpellName(i, BOOKTYPE_SPELL)
	local previousSpellName

	local schoolEnabled = self.db.profile.school

	while spellName do
		if spellName ~= previousSpellName then
			for pattern, replacement in pairs(groupedCooldowns) do
				if (string.find(spellName, pattern)) then
					spellName = replacement
					break
				end
			end

			Gratuity:SetSpell(i, BOOKTYPE_SPELL)

			if Gratuity:Find(L["cooldown"], 2, 3, true) then
				spells[spellName] = {
					id = i,
					icon = GetSpellTexture(i, BOOKTYPE_SPELL),
					startTime = 0,
				}
				if schoolEnabled and schoolSpells[playerClass] and schoolSpells[playerClass][spellName] then
					spells[spellName]["school"] = schoolSpells[playerClass][spellName]
				end
				if chainedCooldowns[spellName] then
					self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
				end
			else
				if schoolEnabled and schoolGroups[playerClass] then
					for school, spell in pairs(schoolGroups[playerClass]) do
						if (spellName == spell) then
							spells[spellName] = {
								id = i,
								icon = GetSpellTexture(i, BOOKTYPE_SPELL),
								startTime = 0,
								school = school,
							}
							break
						end
					end
				end
			end
		end

		i = i + 1
		previousSpellName = spellName
		spellName = GetSpellName(i, BOOKTYPE_SPELL)
	end

	self:SPELL_UPDATE_COOLDOWN()
end

function Hourglass:ScanPetSpells()
	petspells = {}

	local i = 1
	local spellName = GetSpellName(i, BOOKTYPE_PET)
	local previousSpellName

	while spellName do
		if spellName ~= previousSpellName then

			Gratuity:SetSpell(i, BOOKTYPE_PET)

			if Gratuity:Find("cooldown", 2, 3, true) then
				petspells[spellName] = {
					id = i,
					icon = GetSpellTexture(i, BOOKTYPE_PET),
					startTime = 0,
				}
			end
		end

		i = i + 1
		previousSpellName = spellName
		spellName = GetSpellName(i, BOOKTYPE_PET)
	end

	self:PET_BAR_UPDATE_COOLDOWN()
end

function Hourglass:ScanItems()
	for _, slotName in pairs(itemSlots) do
		local slotId = GetInventorySlotInfo(slotName)
		local startTime, duration, enable = GetInventoryItemCooldown("player", slotId)

		if enable == 1 and duration > self.db.profile.min and duration <= self.db.profile.max then
			local name = select(3, GetInventoryItemLink("player", slotId):find("Hitem[^|]+|h%[([^[]+)%]"))

			if items[name] and items[name].name ~= name then
				self:StopCandyBar(self:GetBarId(name))
				self:CancelScheduledEvent(self:GetBarId(name))
				items[name] = nil
			end

			if not items[name] then
				items[name] = {
					name = name,
					icon = GetInventoryItemTexture("player", slotId)
				}
			end

			if items[name].startTime ~= startTime then
				items[name].startTime = startTime;
				self:StartBar(slotName, items[name], duration)
			end
			--self:Print(slotName .. " " .. startTime .. " ".. duration)
		elseif items[name] then
			self:StopCandyBar(self:GetBarId(name))
			self:CancelScheduledEvent(self:GetBarId(name))
			items[name] = nil
		end
	end
end
function Hourglass:ScanBags()
	local slots, id, name, startTime, duration, enable;

	for i=0,4 do
		slots = GetContainerNumSlots(i);
		for j=1,slots do
			startTime, duration, enable = GetContainerItemCooldown(i,j);
			if enable == 1 and duration > self.db.profile.min and duration <= self.db.profile.max then
				_, _, name = string.find(GetContainerItemLink(i,j), "Hitem[^|]+|h%[([^[]+)%]");

				for pattern, replacement in pairs(groupedBagCooldowns) do
					if (string.find(name, pattern)) then
						name = replacement
						break
					end
				end

				if not items[name] then
					items[name] = {
						name = name,
						icon = GetContainerItemInfo(i,j),
					}
				end

				if items[name].startTime ~= startTime then
					items[name].startTime = startTime;
					self:StartBar(name, items[name], duration)
				end
			end
		end
	end
end

function Hourglass:TestBars()
	local testData1 = {
		id = 1,
		icon = "Interface\\Icons\\Spell_Shadow_DeathCoil",
		startTime = GetTime(),
	}
	local testData2 = {
		id = 2,
		icon = "Interface\\Icons\\Spell_Shadow_DeathCoil",
		startTime = GetTime(),
	}
	local testData3 = {
		id = 3,
		icon = "Interface\\Icons\\Spell_Shadow_DeathCoil",
		startTime = GetTime(),
	}

	for i = 1, 3 do
		if self:IsCandyBarRegistered("HourglassTestBar" .. i) then
			self:StopCandyBar(self:GetBarId("HourglassTestBar" .. i))
			self:CancelScheduledEvent(self:GetBarId("HourglassTestBar" .. i))
		end
	end

	self:StartBar("TestBar1", testData1, 7.5)
	self:StartBar("TestBar2", testData2, 5)
	self:StartBar("TestBar3", testData3, 2.5)
end

local function setupEmphasizedGroup()
	local u = Hourglass.db.profile.emphasizeGrowup
	Hourglass:RegisterCandyBarGroup("HourglassEmphasizedGroup")
--	if not emphasizeAnchor then Hourglass:SetupFrames(true) end
	Hourglass:SetCandyBarGroupPoint("HourglassEmphasizedGroup", u and "BOTTOM" or "TOP", emphasizeAnchor, u and "TOP" or "BOTTOM", 0, 0)
	Hourglass:SetCandyBarGroupGrowth("HourglassEmphasizedGroup", u)
end

function Hourglass:StartBar(name, data, duration)
	local barId = self:GetBarId(name)
	local timeLeft = duration - (GetTime() - data.startTime)

	local db = self.db.profile
	local emphasizeTime = db.emphasizeTime or 5
	local scheduleTime = 0.1

	if timeLeft > emphasizeTime then
		scheduleTime = timeLeft - emphasizeTime
	end

	local barText = ""
	if not db.timeOnly then
		barText = data.name and data.name or name
	end

	if db.emphasize and (db.emphasizeMove or db.emphasizeFlash) then
		if db.emphasizeMove then
			if not emphasizeTimers then emphasizeTimers = {} end
			if emphasizeTimers[barId] then self:CancelScheduledEvent(emphasizeTimers[barId]) end
			emphasizeTimers[barId] = "Hourglass-EmphasizeBar-" .. barId
			self:ScheduleEvent(emphasizeTimers[barId], self.EmphasizeBar, scheduleTime, self, barId)
		end
		if db.emphasizeFlash then
			if not flashTimers then flashTimers = {} end
			if flashTimers[barId] then self:CancelScheduledEvent(flashTimers[barId]) end
			flashTimers[barId] = "Hourglass-FlashBar-" .. barId
			self:ScheduleEvent(flashTimers[barId], self.FlashBar, scheduleTime, self, barId)
		end
	end

	self:RegisterCandyBar(barId, duration, barText, data.icon, "Blue", "Red")
	self:RegisterCandyBarWithGroup(barId, "Hourglass")

	self:SetCandyBarTexture(barId, SharedMedia:Fetch("statusbar", db.texture))
	self:SetCandyBarFade(barId, 1)
	self:SetCandyBarTimeLeft(barId, timeLeft)
	self:SetCandyBarScale(barId, db.scale or 1)
	self:SetCandyBarWidth(barId, db.width)
	self:SetCandyBarHeight(barId, db.height)
	self:SetCandyBarFontSize(barId, db.fontsize)
	self:StartCandyBar(barId, true)
	if db.display and (db.display ~= "None") then
		self:ScheduleEvent("HourglassMessage"..name, self.Message, timeLeft, self, data.name and data.name or name)
	end
end

function Hourglass:Message(name)
	self:Pour(name .. " Ready!",.2,.7,.9)
end

function Hourglass:GetBarId(name)
	return "Hourglass" .. name
end

function Hourglass:ShowOptions()
	Dewdrop:Open("Hourglass")
end

function Hourglass:CreateAnchor()
	anchor = CreateFrame("Button", "HourglassFrame", UIParent)
	anchor:Hide()
	anchor:SetWidth(200)
	anchor:SetHeight(16)
	anchor:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16})
	anchor:SetBackdropColor(0.3, 0.3, 0.3, 0.7)

	anchor:SetMovable(true)
	anchor:RegisterForDrag("LeftButton")
	anchor:RegisterForClicks("RightButtonUp")

	anchor:SetScript("OnClick", function (this) self:ShowOptions() end)
	anchor:SetScript("OnDragStart", function(this) this:StartMoving() end)
	anchor:SetScript("OnDragStop", function(this)
		this:StopMovingOrSizing()
		self.db.profile.x = this:GetLeft()
		self.db.profile.y = this:GetTop()
-- 		self:SetCandyBarGroupPoint("Hourglass", "TOPLEFT", UIParent, "BOTTOMLEFT", self.db.profile.x, self.db.profile.y)
	end)

	anchor:SetFont(GameFontHighlightSmall:GetFont(), 10)
	anchor:SetText("Hourglass")

	if not self.db.profile.x then
		anchor:SetPoint("CENTER", UIParent, "CENTER", 0, -200)
	else
		anchor:ClearAllPoints()
		anchor:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", self.db.profile.x, self.db.profile.y)
	end

	-- Emphasize
	emphasizeAnchor = CreateFrame("Button", "HourglassEmphasizeFrame", UIParent)
	emphasizeAnchor:Hide()
	emphasizeAnchor:SetWidth(200)
	emphasizeAnchor:SetHeight(16)
	emphasizeAnchor:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16})
	emphasizeAnchor:SetBackdropColor(0.3, 0.3, 0.3, 0.7)

	emphasizeAnchor:SetMovable(true)
	emphasizeAnchor:RegisterForDrag("LeftButton")
	emphasizeAnchor:RegisterForClicks("RightButtonUp")

	emphasizeAnchor:SetScript("OnClick", function (this) self:ShowOptions() end)
	emphasizeAnchor:SetScript("OnDragStart", function(this) this:StartMoving() end)
	emphasizeAnchor:SetScript("OnDragStop", function(this)
		this:StopMovingOrSizing()
		self.db.profile.emphasizePosX = this:GetLeft()
		self.db.profile.emphasizePosY = this:GetTop()
-- 		self:SetCandyBarGroupPoint("Hourglass", "TOPLEFT", UIParent, "BOTTOMLEFT", self.db.profile.x, self.db.profile.y)
	end)

	emphasizeAnchor:SetFont(GameFontHighlightSmall:GetFont(), 10)
	emphasizeAnchor:SetText("HourglassEmphasize")

	if not self.db.profile.PosX then
		emphasizeAnchor:SetPoint("CENTER", UIParent, "CENTER", 0, -200)
	else
		emphasizeAnchor:ClearAllPoints()
		emphasizeAnchor:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", self.db.profile.PosX, self.db.profile.PosY)
	end
end

function Hourglass:ToggleAnchor(show)
	if show then
		Dewdrop:Close()
		anchor:Show()
		emphasizeAnchor:Show()
	else
		anchor:Hide()
		emphasizeAnchor:Hide()
	end
end

------------------------------
-- Emphasize (from BigWigs) --
------------------------------


-----------------------------------------------------------------------
--    Emphasized Background Flashing
-----------------------------------------------------------------------

local flashColors
local generateColors
do
	local function ColorGradient(perc, ...)
		if perc >= 1 then
			local r, g, b = select(select("#", ...) - 2, ...)
			return r, g, b
		elseif perc <= 0 then
			local r, g, b = ...
			return r, g, b
		end
		local num = select("#", ...) / 3
		local segment, relperc = math.modf(perc*(num-1))
		local r1, g1, b1, r2, g2, b2 = select((segment*3)+1, ...)
		return r1 + (r2-r1)*relperc, g1 + (g2-g1)*relperc, b1 + (b2-b1)*relperc
	end
	generateColors = function()
		flashColors = {}
		for i = 0.1, 1, 0.1 do
			local r, g, b = ColorGradient(i, 255,0,0, 0,0,0)
			local hex = ("%02x%02x%02x"):format(r, g, b)
			paint:RegisterHex(hex) -- We have to do this because CandyBar fails silently on hex codes not registered with paintchips ...
			table.insert(flashColors, hex:lower()) -- hex:lower() because that's what PaintChips uses for the "name" .. wtf.
		end
	end
end

local flashBarUp, flashBarDown

local currentColor = {}
flashBarUp = function(id)
	Hourglass:SetCandyBarBackgroundColor(id, flashColors[currentColor[id]], 0.5)
	if currentColor[id] == #flashColors then
		Hourglass:ScheduleRepeatingEvent(id, flashBarDown, 0.1, id)
		return
	end
	currentColor[id] = currentColor[id] + 1
end
flashBarDown = function(id)
	Hourglass:SetCandyBarBackgroundColor(id, flashColors[currentColor[id]], 0.5)
	if currentColor[id] == 1 then
		Hourglass:ScheduleRepeatingEvent(id, flashBarUp, 0.1, id)
		return
	end
	currentColor[id] = currentColor[id] - 1
end

function Hourglass:FlashBar(id)
	if not flashColors then generateColors() end
	if flashTimers then flashTimers[id] = nil end
	-- Start flashing the bar
	currentColor[id] = 1
	self:ScheduleRepeatingEvent(id, flashBarUp, 0.1, id)
	self:ScheduleEvent(self.CancelScheduledEvent, 5, self, id)
end

-----------------------------------------------------------------------
--    Smooth Moving of Emphasized Bars
-----------------------------------------------------------------------

-- copied from PitBull_BarFader
local function CosineInterpolate(y1, y2, mu)
	local mu2 = (1-_cos(mu*_pi))/2
	return y1*(1-mu2)+y2*mu2
end

function Hourglass:UpdateBars()
	local now, count = GetTime(), 0

	for bar, opt in pairs(movingBars) do
		local stop, scale = opt.stop
		count = count + 1
		if stop < now then
			movingBars[bar] = del(movingBars[bar])
			self:RegisterCandyBarWithGroup(bar, "HourglassEmphasizedGroup")
			self:SetCandyBarScale(bar, Hourglass.db.profile.emphasizeScale or 1)
			return
		end

		local centerX, centerY = self:GetCandyBarCenter(bar)
		if type(centerX) == "number" and type(centerY) == "number" then
			local effscale = self:GetCandyBarEffectiveScale(bar)
			local tempX, tempY = centerX*effscale, centerY*effscale

			tempX = CosineInterpolate(tempX, opt.targetX, 1 - ((stop - now) / DURATION) )
			tempY = CosineInterpolate(tempY, opt.targetY, 1 - ((stop - now) / DURATION) )
			scale = (opt.stopScale - opt.startScale) * (1 - ((stop - now) / DURATION))

			self:SetCandyBarScale(bar, scale + opt.startScale)
			effscale = self:GetCandyBarEffectiveScale(bar)

			local point, rframe, rpoint = self:GetCandyBarPoint(bar)
			self:SetCandyBarPoint(bar, point, rframe, rpoint, tempX/effscale, tempY/effscale)
		end
	end

	if count == 0 then
		self:CancelScheduledEvent("HourglassBarMover")
	end
end

function Hourglass:EmphasizeBar(id)
	local centerX, centerY = self:GetCandyBarCenter(id)
	if type(centerX) ~= "number" or type(centerY) ~= "number" then return end

	if emphasizeTimers then emphasizeTimers[id] = nil end

	setupEmphasizedGroup()

	if not self:IsEventScheduled("HourglassBarMover") then
		self:ScheduleRepeatingEvent("HourglassBarMover", self.UpdateBars, 0, self)
	end

	self:UnregisterCandyBarWithGroup(id, "Hourglass")
	self:SetCandyBarPoint(id, "CENTER", "UIParent", "BOTTOMLEFT", centerX, centerY)

	local targetX, targetY = self:GetCandyBarNextBarPointInGroup("HourglassEmphasizedGroup")

	local db = Hourglass.db.profile
	local u = db.emphasizeGrowup

	local offsetTop, offsetBottom = select(2, self:GetCandyBarOffsets(id))
	local offsetY = u and centerY - offsetBottom or centerY - offsetTop

	local frameX = emphasizeAnchor:GetCenter()
	local frameY = u and emphasizeAnchor:GetTop() or emphasizeAnchor:GetBottom()
	local frameScale = emphasizeAnchor:GetEffectiveScale()

	movingBars[id] = new()
	movingBars[id].stop = GetTime() + DURATION
	movingBars[id].targetX = (targetX * (UIParent:GetEffectiveScale() * db.emphasizeScale or 1)) + (frameX * frameScale)
	movingBars[id].targetY = (targetY * (UIParent:GetEffectiveScale() * db.emphasizeScale or 1)) + ((frameY + offsetY) * frameScale)
	movingBars[id].startScale = db.scale or 1
	movingBars[id].stopScale = db.emphasizeScale or 1
end







